package com.game.logic.channel;

import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.BiConsumer;

@Slf4j
@Service
public class ClientChannelService {
	// userId与Netty， Channel的映射容器，这里使用的是HashMap，所以，对于Map的操作都要放在锁里面
	private Map<Long, Channel> playerChannelMap = new HashMap<>();

	// 读写锁,使用非公平锁
	private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

	// 封装添加读锁，统一添加，防止写错
	private void readLock(Runnable task) {
		try {
			lock.readLock().lock();
			task.run();
		} catch (Exception e) {
			// 统一异常捕获
			log.error("ChannelService读锁处理异常 :{} ", e.getMessage());
		} finally {
			lock.readLock().unlock();
		}
	}

	// 封装添加写锁，统一添加，防止写错
	private void writeLock(Runnable task) {
		lock.writeLock().lock();
		try {
			task.run();
		} catch (Exception e) {
			// 统一异常捕获
			log.error("ChannelService写锁处理异常 :{} ", e.getMessage());
		} finally {
			lock.writeLock().unlock();
		}
	}

	public void addChannel(Long userId, Channel channel) {
		try {
			// 数据写入，添加写锁
			this.writeLock(() -> {
				playerChannelMap.put(userId, channel);
				channel.closeFuture().addListener(future -> {
					log.debug("addChannel userId: {} 连接 channelId: {} 断开",
							userId, channel.id().asShortText());
					removeChannel(userId, channel);
				});
			});
		}catch (Exception e){
			log.error("ChannelService写锁处理异常 :{} ", e.getMessage());
		}
	}

	public Channel getChannel(Long userId) {
		lock.readLock().lock();
		try {
			Channel channel = this.playerChannelMap.get(userId);
			log.debug("getChannel channelId:{} ", channel.id().asShortText());
			return channel;
		}catch (Exception e){
			log.error("ChannelService写锁处理异常 :{} ", e.getMessage());
		}finally {
			lock.readLock().unlock();
		}
		return null;
	}

	// 必须是同一个对象才可以移除
	public void removeChannel(Long userId, Channel removedChannel) {
		try {
			this.writeLock(() -> {
				Channel existChannel = playerChannelMap.get(userId);
				if ((existChannel != null)
						&& (existChannel == removedChannel)) {
					playerChannelMap.remove(userId);
					existChannel.close();
				}
			});
		}catch (Exception e){
			log.error("ChannelService写锁处理异常 :{} ", e.getMessage());
		}
	}

	// 向Channel广播消息
	public void broadcast(BiConsumer<Long, Channel> consumer) {
		this.readLock(() -> {
			this.playerChannelMap.forEach(consumer);
		});
	}

	// 获取连锁的数量
	public int getChannelCount() {
		lock.writeLock().lock();
		try {
			int size = this.playerChannelMap.size();
			log.debug("getChannelCount size:{} ", size);
			return size;
		} finally {
			lock.writeLock().unlock();
		}
	}

}
